package com.yunsc.store.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunsc.common.exception.YunscException;
import com.yunsc.common.utils.PageResult;
import com.yunsc.common.utils.RedisUtils;
import com.yunsc.store.dao.YunscUserCouponDao;
import com.yunsc.store.dto.ApplyRangeConfigDTO;
import com.yunsc.store.dto.CouponReceiveDTO;
import com.yunsc.store.entity.YunscCouponEntity;
import com.yunsc.store.entity.YunscUserCouponEntity;
import com.yunsc.store.service.YunscCouponService;
import com.yunsc.store.service.YunscUserCouponService;
import com.yunsc.store.service.YunscUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yunsc.common.utils.DateUtils.convertStringToSeconds;
import static com.yunsc.common.utils.PageResult.formatPageResult;

@Slf4j
@Service("yunscUserCouponService")
public class YunscUserCouponServiceImpl extends ServiceImpl<YunscUserCouponDao, YunscUserCouponEntity> implements YunscUserCouponService {

    @Resource
    private YunscCouponService couponService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private YunscUserCouponService userCouponService;
    @Resource
    private YunscUserService userService;
    @Resource
    private RedisUtils redisUtils;
    private static final int CORE_POOL_SIZE = 5; // 根据需要调整核心线程数
    private static final int MAXIMUM_POOL_SIZE = 10; // 根据需要调整最大线程数
    private static final long KEEP_ALIVE_TIME = 60L; // 空闲线程存活时间，单位秒
    private static final TimeUnit UNIT = TimeUnit.SECONDS;
    private static final BlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingQueue<>(100); // 阻塞队列容量，根据需要调整

    // 在类加载时初始化线程池
    private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAXIMUM_POOL_SIZE,
            KEEP_ALIVE_TIME,
            UNIT,
            WORK_QUEUE,
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略，这里选择调用者运行策略作为示例
    );

    // 关闭线程池
    public static void shutdownThreadPoolGracefully() {
        THREAD_POOL_EXECUTOR.shutdown();
        try {
            if (!THREAD_POOL_EXECUTOR.awaitTermination(60, TimeUnit.SECONDS)) {
                THREAD_POOL_EXECUTOR.shutdownNow();
                if (!THREAD_POOL_EXECUTOR.awaitTermination(60, TimeUnit.SECONDS))
                    System.err.println("Pool did not terminate");
            }
        } catch (InterruptedException ie) {
            THREAD_POOL_EXECUTOR.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    // 使用线程池执行任务
    private void asyncUpdateCouponExpiration(List<YunscUserCouponEntity> coupons, Integer userId) {
        THREAD_POOL_EXECUTOR.execute(() -> {
            // 执行任务
        });
    }

    @Override
    @Transactional
    public int queryUserCoupon(Integer userId) {
        LambdaQueryWrapper<YunscUserCouponEntity> lqw = new LambdaQueryWrapper<>();
        lqw.eq(YunscUserCouponEntity::getUserId, userId);
        lqw.eq(YunscUserCouponEntity::getIsExpire, 0);
        lqw.eq(YunscUserCouponEntity::getIsUse, 0);
        return this.count(lqw);
    }

    @Override
    public List<YunscUserCouponEntity> queryUserCouponById(Integer userCouponId, Integer userId) {
        long nowTime = Instant.now().toEpochMilli() / 1000;
        LambdaQueryWrapper<YunscUserCouponEntity> lqw = new LambdaQueryWrapper<>();
        if (userCouponId != null && userCouponId > 0) {
            lqw.eq(YunscUserCouponEntity::getUserCouponId, userCouponId);
        }
        lqw.eq(YunscUserCouponEntity::getUserId, userId);
        // todo是否过期
        lqw.eq(YunscUserCouponEntity::getIsExpire, 0);
        // 是否已使用
        lqw.eq(YunscUserCouponEntity::getIsUse, 0);
        // 开始时间小于当前时间
        lqw.lt(YunscUserCouponEntity::getStartTime, nowTime);
        // 结束时间大于当前时间
        lqw.gt(YunscUserCouponEntity::getEndTime, nowTime);
        List<YunscUserCouponEntity> list = this.list(lqw);
        list.forEach(this::setIsExpireCoupon);
        return list;
    }

    @Override
    public void receiveCoupon(Integer couponId, Integer userId) {
        // 1.查询优惠券
        YunscCouponEntity coupon = couponService.getById(couponId);
        if (coupon == null) {
            throw new YunscException("优惠券不存在");
        }
        // 2.判断库存是否充足
        if (coupon.getTotalNum() < 1 && coupon.getTotalNum() != -1) {
            // -1为不限制
            throw new YunscException("优惠券库存不足！");
        }

        // 到期类型(10领取后生效 20固定时间)
        Integer expireType = coupon.getExpireType();
        if (expireType == 10) {
            // 10领取后生效
            userCouponService.createUserCoupon(coupon, userId);
            return;
        }

        // 20 固定时间
        // 2.判断秒杀是否开始
        if (coupon.getStartTime() > Instant.now().getEpochSecond()) {
            throw new YunscException("秒杀尚未开始！");
        }
        // 3.判断秒杀是否已经结束
        if (coupon.getEndTime() < Instant.now().getEpochSecond()) {
            throw new YunscException("秒杀已经结束！");
        }
        // 执行优惠券下单逻辑
        userCouponService.createUserCoupon(coupon, userId);

    }

    @Override
    public PageResult<YunscUserCouponEntity> queryUserCouponList(String dataType, Integer page, Integer userId) {

        LambdaQueryWrapper<YunscUserCouponEntity> lqw = new LambdaQueryWrapper<>();
        if (page == null || page == 0) {
            page = 1;
        }
        lqw.eq(YunscUserCouponEntity::getUserId, userId);
        lqw.orderByAsc(YunscUserCouponEntity::getEndTime);
        // 是否未使用
        if ("isUnused".equals(dataType)) {
            lqw.eq(YunscUserCouponEntity::getIsUse, 0);
            lqw.eq(YunscUserCouponEntity::getIsExpire, 0);
        }
        // 是否已使用
        lqw.eq("isUse".equals(dataType), YunscUserCouponEntity::getIsUse, 1);
        //  是否过期
        lqw.eq("isExpire".equals(dataType), YunscUserCouponEntity::getIsExpire, 1);
        Page<YunscUserCouponEntity> page1 = new Page<>(page, 15);
        Page<YunscUserCouponEntity> pageResult = this.page(page1, lqw);
        List<YunscUserCouponEntity> records = pageResult.getRecords();
        records.forEach(this::setIsExpireCoupon);
        return formatPageResult(records, page, 15, pageResult.getTotal());
    }


    @Override
    @Transactional
    public void updateCouponExpiration(List<YunscUserCouponEntity> coupons) {
        // 过滤出过期的优惠券
        List<YunscUserCouponEntity> expiredCoupons = coupons.stream()
                .filter(coupon -> Instant.now().getEpochSecond() > coupon.getEndTime())
                .peek(coupon -> coupon.setIsExpire(1))
                .collect(Collectors.toList());

        if (expiredCoupons.isEmpty()) {
            log.info("没有过期的优惠券");
            return;
        }
        // 批量更新过期优惠券状态
        log.info("更新过期优惠券状态：{}", expiredCoupons.stream().map(YunscUserCouponEntity::getCouponId).collect(Collectors.toList()));
        userCouponService.updateBatchById(expiredCoupons);
    }

    @Override
    public List<YunscUserCouponEntity> queryUserCouponList(Integer userId) {
        LambdaQueryWrapper<YunscUserCouponEntity> lqw = new LambdaQueryWrapper<>();
        lqw.eq(YunscUserCouponEntity::getUserId, userId);
        lqw.eq(YunscUserCouponEntity::getIsExpire, 0);
        lqw.eq(YunscUserCouponEntity::getIsUse, 0);
        List<YunscUserCouponEntity> list = this.list(lqw);
        return list;
    }

    @Override
    public List<YunscUserCouponEntity> queryGoodsAvailableCoupons(Integer userCouponId, Integer userId, BigDecimal orderTotalPrice, List<Integer> goodsIds) {
        List<YunscUserCouponEntity> couponList = queryUserCouponList(userId);
        List<YunscUserCouponEntity> availableCoupons = new ArrayList<>();

        if (couponList.isEmpty()) {
            // 如果用户优惠券列表为空，根据业务需求返回默认值或抛出异常
            return availableCoupons; // 或者根据业务需求抛出异常
        }

        for (YunscUserCouponEntity coupon : couponList) {
            setIsCouponApplicable(coupon, orderTotalPrice, goodsIds);
            availableCoupons.add(coupon);
        }

        return availableCoupons;
    }

    @Override
    public PageResult<YunscUserCouponEntity> queryCouponReceivePageList(CouponReceiveDTO param, Integer storeId) {
        // Page<YunscUserCouponEntity> userCouponPage = this.baseMapper.selectUserCouponPage(
        //         new Page<>(param.getPage(), param.getPageSize()),
        //         param,
        //         storeId,
        //         DateUtils.convertIntToSeconds(param.getBetweenTimeStart()),
        //         DateUtils.convertIntToSeconds(param.getBetweenTimeEnd())
        // );


        LambdaQueryWrapper<YunscUserCouponEntity> lqw = new LambdaQueryWrapper<>();
        if (param.getBetweenTimeStart() != null && param.getBetweenTimeEnd() != null){
            long start = convertStringToSeconds(param.getBetweenTimeStart());
            long end = convertStringToSeconds(param.getBetweenTimeEnd());
            lqw.between(YunscUserCouponEntity::getCreateTime, start, end);
        }
        lqw.like(StringUtils.isNotEmpty(param.getCouponName()), YunscUserCouponEntity::getName, param.getCouponName());
        lqw.orderByDesc(YunscUserCouponEntity::getCreateTime);
        Page<YunscUserCouponEntity> userCouponPage = this.page(new Page<>(param.getPage(), param.getPageSize()), lqw);
        List<YunscUserCouponEntity> userCouponList = userCouponPage.getRecords();
        userCouponList.forEach(userCouponEntity -> userCouponEntity.setUser(userService.queryUserInfo(userCouponEntity.getUserId())));

        if (StringUtils.isNotEmpty(param.getNickName())){
            userCouponList = userCouponList.stream().filter(userCouponEntity -> userCouponEntity.getUser().getNickName().contains(param.getNickName())).collect(Collectors.toList());
        }

        return PageResult.formatPageResult(userCouponList, param.getPage(), param.getPageSize(), userCouponPage.getTotal());
    }


    private void setIsCouponApplicable(YunscUserCouponEntity coupon, BigDecimal orderTotalPrice, List<Integer> goodsIds) {
        if (coupon.getApplyRange() == 20 && !coupon.getApplyRangeConfig().equals("[]")) {
            // 指定商品可用
            ApplyRangeConfigDTO applyRangeConfigDTO = JSON.parseObject((String)coupon.getApplyRangeConfig(), ApplyRangeConfigDTO.class);
            List<Integer> applyGoodsIds = applyRangeConfigDTO.getApplyGoodsIds();
            if (!Collections.disjoint(goodsIds, applyGoodsIds)) {
                // 商品列表与适用商品列表有交集，则该优惠券可用
                coupon.setIsApply(true);
            } else {
                coupon.setIsApply(false);
                coupon.setNotApplyInfo("该优惠券不适用该商品");
            }
        } else if (coupon.getApplyRange() == 10) {
            // 全场可用，判断是否满足最低消费金额
            String minPrice = coupon.getMinPrice();
            if (orderTotalPrice.compareTo(new BigDecimal(minPrice)) >= 0) {
                // 订单金额大于等于最低消费金额，该优惠券可用
                coupon.setIsApply(true);
            } else {
                coupon.setIsApply(false);
                coupon.setNotApplyInfo("订单金额小于最低消费金额，不适用该优惠券");
            }
        } else {
            // 其他情况，该优惠券不适用
            coupon.setIsApply(false);
            coupon.setNotApplyInfo("该优惠券不适用");
        }

        setIsExpireCoupon(coupon);
    }

    private void setIsExpireCoupon(YunscUserCouponEntity coupon) {
        // 获取当前时间戳
        long nowTimestamp = Instant.now().toEpochMilli() / 1000;
        // 判断当前时间是否在优惠券有效期内
        if (coupon.getIsUse() == 0 && nowTimestamp >= coupon.getStartTime() && nowTimestamp <= coupon.getEndTime()) {
            Map<String, Object> map = new HashMap<>();
            map.put("text", "正常");
            map.put("value", 1);
            coupon.setState(map);
        } else if (coupon.getIsUse() == 1) {
            Map<String, Object> map = new HashMap<>();
            map.put("text", "已使用");
            map.put("value", 0);
            coupon.setState(map);
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("text", "已过期");
            map.put("value", 0);
            coupon.setIsExpire(1);
            coupon.setState(map);
        }
    }

    @Override
    @Transactional
    public void createUserCoupon(YunscCouponEntity coupon, Integer userId) {
        // 创建分布式锁对象
        RLock lock = redissonClient.getLock("lock:coupon:" + userId);
        // 获取锁对象
        boolean isLock = lock.tryLock();
        // 加锁失败
        if (!isLock) {
            throw new YunscException("抢购失败，请稍后再试！");
        }
        try {
            // 1.一人一单逻辑
            int count = this.query().eq("user_id", userId).eq("coupon_id", coupon.getCouponId()).count();
            // 2.判断是否存在
            if (count > 0) {
                log.error("用户[" + userId + "]已经购买过一次！");
                throw new YunscException("已领取过该优惠券！");
            }
            // 3.扣减库存
            boolean update;
            if (coupon.getTotalNum() != -1) {
                update = couponService.update(new UpdateWrapper<YunscCouponEntity>()
                        .eq("coupon_id", coupon.getCouponId())
                        .setSql("total_num = total_num - 1")
                        .setSql("receive_num = receive_num + 1")
                        .gt("total_num", 0)
                );
            } else {
                // -1为不限制库存
                update = couponService.update(new UpdateWrapper<YunscCouponEntity>()
                        .eq("coupon_id", coupon.getCouponId())
                        .setSql("receive_num = receive_num + 1")
                );
            }

            if (!update) {
                log.error("库存减少失败");
                throw new YunscException("库存减少失败");
            }

            // 4.创建订单
            YunscUserCouponEntity userCoupon = new YunscUserCouponEntity();
            BeanUtils.copyProperties(coupon, userCoupon);
            // 到期类型(10领取后生效 20固定时间)
            if (coupon.getExpireType() == 10) {
                Integer expireDay = coupon.getExpireDay();
                // 计算优惠券的开始时间毫秒值（领取后立即生效）
                long startMillis = Instant.now().toEpochMilli();
                // 计算优惠券的结束时间毫秒值（领取后七天内有效）
                long endMillis = startMillis + expireDay * 24 * 60 * 60 * 1000; // 加上七天的毫秒数
                userCoupon.setStartTime((int) (startMillis / 1000));
                userCoupon.setEndTime((int) (endMillis / 1000));
            } else if (coupon.getExpireType() == 20) {
                // 固定时间
                userCoupon.setStartTime(coupon.getStartTime());
                userCoupon.setEndTime(coupon.getEndTime());
            }
            userCoupon.setCouponId(coupon.getCouponId());
            userCoupon.setUserId(userId);
            this.save(userCoupon);
        } finally {
            // 释放锁
            lock.unlock();
        }

    }

}